﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;

namespace _404park.Utilities.Web
{
    public class HostResolver
    {
        private static List<string> _TLDList = null;
        private static HostResolver _instance;

        static HostResolver()
        {
            _TLDList = XmlParser.GetNodeValues(@"_404park.Utilities.DATA.TLD.xml", @"/TLDList/name", null);
            _instance = new HostResolver();
        }

        public static HostResolver Instance()
        {
            return _instance;
        }

        public string ResolveHost(HttpRequest Request, HttpResponse Response)
        { 
            return ResolveHost(new HttpRequestWrapper(Request), new HttpResponseWrapper(Response)); 
        }


        public string ResolveHost(HttpRequestBase Request, HttpResponseBase Response)
        {
            string host = "";

            try
            {
                if (Request.QueryString != null && Request.QueryString["dom"] != null)
                {
                    // Check Query String for dom parameter - Used while debugging
                    GetHost(Request.QueryString["dom"], out host);
                    WriteCookie("host", host, 0, Response);
                }
                else if (ReadCookie("host", Request).Length > 0)
                {
                    // Check Cookie to host the same template irrespective of servers.
                    host = ReadCookie("host", Request);
                }
                else
                {
                    GetHost(Request.Url.Host, out host);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return host;
        }

        public bool GetHost(string host, out string domain)
        {
            bool res = true;
            domain = "";

            if (host == null)   // NULL OBJECT
                return false;

            if (host.EndsWith("."))
                host = host.Substring(0, host.Length - 1);
            else if (host.ToLower().StartsWith(@"www."))
                host = host.Substring(4, host.Length - 4);

            // if host is a valid ip, return as is
            if (ValidIPAddress(host))
            {
                domain = host;
                res = false;
            }
            else
            {

                string[] hostParts = host.Split(new char[] { '.' });
                int idx = hostParts.Length;
                string ext = "";
                switch (idx)
                {
                    case 1:     // NO TLD
                        res = false;
                        domain = host;
                        break;
                    case 2:     // PRIMARY TLD
                        ext = hostParts[idx - 1].ToLower();
                        domain = host;
                        if (!_TLDList.Contains(ext))
                            res = false;
                        break;
                    case 3:     // SECONDARY TLD OR SUB-DOMAIN
                        ext = hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower(); // SECOND LEVEL
                        if (_TLDList.Contains(ext))
                            domain = host;
                        else
                        {
                            domain = hostParts[idx - 2] + "." + hostParts[idx - 1];             // PRIMARY LEVEL
                            if (!_TLDList.Contains(hostParts[idx - 1].ToLower()))
                                res = false;
                        }
                        break;
                    default:
                        ext = hostParts[idx - 3].ToLower() + "." + hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower();
                        if (_TLDList.Contains(ext))
                            domain = hostParts[idx - 4].ToLower() + "." + hostParts[idx - 3].ToLower() + "." + hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower();
                        else
                        {
                            ext = hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower();
                            if (_TLDList.Contains(ext))
                                domain = hostParts[idx - 3].ToLower() + "." + hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower();
                            else
                            {
                                domain = hostParts[idx - 2] + "." + hostParts[idx - 1];
                                if (!_TLDList.Contains(hostParts[idx - 1].ToLower()))
                                    res = false;
                            }
                        }
                        break;
                }
            }
            return res;
        }

        public bool GetSearchTerm(string host, out string searchTerm)
        {
            bool res = true;
            searchTerm = "";

            if (host == null)   // NULL OBJECT
                return false;
            
            if (host.EndsWith("."))
                host = host.Substring(0, host.Length - 1);
            else if(host.ToLower().StartsWith(@"www."))
                host = host.Substring(4, host.Length - 4);
            
            // if host is a valid ip, return as is
            if (ValidIPAddress(host))
            {
                searchTerm = host;
                res = false;
            }
            else
            {
                
                string[] hostParts = host.Split(new char[] { '.' });
                int idx = hostParts.Length;
                string ext = "";
                string subDomain = string.Empty;
                switch (idx)
                { 
                    case 1:     // NO TLD
                        res = false;
                        searchTerm = host;
                        break;
                    case 2:     // PRIMARY TLD yahoo.com
                        ext = hostParts[idx - 1].ToLower();
                        searchTerm = host;
                        if (!_TLDList.Contains(ext))
                            res = false;
                        break;
                    case 3:     // SECONDARY TLD OR SUB-DOMAIN vn.yahoo.com or yahoo.com.vn
                        ext = hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower(); // SECOND LEVEL
                        if (_TLDList.Contains(ext))
                        {
                            searchTerm = host;
                        }
                        else
                        {
                            searchTerm = hostParts[idx - 2] + "." + hostParts[idx - 1];             // PRIMARY LEVEL
                            subDomain = hostParts[idx - 3];
                            if (!_TLDList.Contains(hostParts[idx - 1].ToLower()))
                                res = false;
                        }
                        break;
                    default:
                        ext = hostParts[idx - 3].ToLower() + "." + hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower();
                        if (_TLDList.Contains(ext))
                        {
                            searchTerm = hostParts[idx - 4].ToLower() + "." + hostParts[idx - 3].ToLower() + "." + hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower();
                            subDomain = hostParts[idx-5];
                        }
                        else
                        {
                            ext = hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower();
                            if (_TLDList.Contains(ext))
                            {
                                searchTerm = hostParts[idx - 3].ToLower() + "." + hostParts[idx - 2].ToLower() + "." + hostParts[idx - 1].ToLower();
                                subDomain = hostParts[idx - 4];
                            }
                            else
                            {
                                searchTerm = hostParts[idx - 2] + "." + hostParts[idx - 1];
                                subDomain = string.Concat(hostParts[idx - 4], " ", hostParts[idx - 3]);
                                if (!_TLDList.Contains(hostParts[idx - 1].ToLower()))
                                    res = false;
                            }
                        }
                        break;
                }

                searchTerm = searchTerm.Split(new char[] { '.' })[0];
                searchTerm = string.IsNullOrEmpty(subDomain) ? searchTerm : string.Concat(subDomain, " ", searchTerm);
            }
            return res;
        }

        public string GetSearchTerm(string host)
        {
            if (host == null)   // NULL OBJECT
                return string.Empty;

            if (host.EndsWith("."))
                host = host.Substring(0, host.Length - 1);
            else if (host.ToLower().StartsWith(@"www."))
                host = host.Substring(4, host.Length - 4);

            string[] hostParts = host.Split(new char[] { '.' });
            int length = hostParts.Length;
            string extension = string.Empty;
            var searchTerm = host;

            if (length == 1)
                return host;

            try {
                int i = 1;
                while (i < length)
                {
                    extension = GetParts(host, i, length - i);
                    if (_TLDList.Contains(extension))
                    {
                        searchTerm = GetParts(host, 0, i).Replace(".", " ");
                        break;
                    }
                    else
                        i++;
                }
            }
            catch (Exception ex)
            {
            }

            return searchTerm;
        }

        private string GetParts(string host, int start, int count)
        {
            string[] hostParts = host.Split(new char[] { '.' });
            
            if (start > hostParts.Length || start + count > hostParts.Length) return string.Empty;

            string extension = string.Empty;
            
            for (int i = start; i < start + count; i++)
            {
                extension += hostParts[i] + " ";
            }

            return extension.Trim().Replace(" ", ".");
        }

        public string RemoveSubdomainAndQueryString(Uri url)
        {
            string result = null;

            string domain = "";
            GetHost(url.Host, out domain);
            result = url.Scheme + "://" + domain;

            int port = url.Port;
            if (port > 0 && port != 80)
            {
                result = result + ":" + url.Port.ToString();
            }

            result = result + RemoveQ(url.PathAndQuery);

            return result;
        }

        public string RemoveQ(string aString)
        {
            string[] strArr = { };

            if (null != aString)
            {
                Regex regEx = new Regex("\\?");
                Match m1 = regEx.Match(aString);

                if (m1.Success)
                {
                    strArr = regEx.Split(aString);
                }

                if (strArr.Length > 0)
                {
                    aString = strArr[0];
                }
            }

            return aString;
        }

        public bool ValidIPAddress(String text)
        {
            if (IsEmpty(text))
                return false;
            Regex re = new Regex(@"^((0|1[0-9]{0,2}|2[0-9]{0,1}|2[0-4][0-9]|25[0-5]|[3-9][0-9]{0,1})\.){3}(0|1[0-9]{0,2}|2[0-9]{0,1}|2[0-4][0-9]|25[0-5]|[3-9][0-9]{0,1})$");
            return re.IsMatch(text);
        }

        public bool IsEmpty(String value)
        {
            bool test = false;

            if (value == null)
                test = true;
            else if (value.Trim().Equals(""))
                test = true;

            return test;
        }

        public void WriteCookie(string CookieName, string CookieValue, int DaysToCookie, HttpResponseBase Response)
        {
            if (Response != null)
            {
                if (CookieName != null && CookieValue != null && CookieName.Length > 0 && CookieValue.Length > 0)
                {
                    HttpCookie _Cookie = new HttpCookie(CookieName, CookieValue);           // Create cookie with Name and Value
                    if (DaysToCookie > 0)                                                   // Session cookies does not have expiry
                    {
                        _Cookie.Expires = DateTime.Now.AddDays(DaysToCookie);               // IF DaysToCookie > 0 set its expiry date
                    }
                    Response.Cookies.Add(_Cookie);           // Add Cookie to Response Object
                }
            }
        }

        public void WriteCookie(string CookieName, string CookieValue, int DaysToCookie, HttpResponse Response)
        { 
            WriteCookie(CookieName, CookieValue, DaysToCookie, new HttpResponseWrapper(Response)); 
        }

        public string ReadCookie(string CookieName, HttpRequestBase Request)
        {
            string _CookieValue = string.Empty;                                         // Return variable
            if (CookieName != null && CookieName.Length > 0)                            // Validate Input
            {                                                                           // Valiate Cookie existence
                if (Request != null &&
                    Request.Cookies[CookieName] != null &&
                    Request.Cookies[CookieName].Value != null &&
                    Request.Cookies[CookieName].Value.Trim().Length > 0)
                {
                    _CookieValue = Request.Cookies[CookieName].Value.Trim();            // Assign Cookie Value
                }
            }
            return _CookieValue;                                                        // Return Cookie Value
        }

        public string ReadCookie(string CookieName, HttpRequest Request)
        { 
            return ReadCookie(CookieName, new HttpRequestWrapper(Request)); 
        }

    }
}
